
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;
using System;
using Newtonsoft.Json;  //引用命名空间
using System.Linq;

// NetManager定义
public static class NetManager
{
    public enum NetEvent
    {
        ConnectSucc = 1,
        ConnectFail = 2,
        Close = 3,
    }

    static Socket socket;
    static int len_readbuff = 1024;
    static ByteArray readBuff = new ByteArray(len_readbuff);

    static int head_len = 2;  // 消息头的长度, int16则为2字节, int32则4字节

    static int len_sendbytes = 1024;
    static byte[] sendBytes = new byte[len_sendbytes];

    static Queue<ByteArray> writeQueue = new Queue<ByteArray>();

    static bool isConnecting = false;
    static bool isClosing = false;
    public static bool hasSendCloseMsg = false;

    // static bool NoDelay = false;

    // 委托类型
    public delegate void EventListener(String err);

    private static Dictionary<NetEvent, EventListener> eventListeners = new Dictionary<NetEvent, EventListener>();

    public delegate void MsgListener(String str);
    // public delegate void MsgListener(MsgBase msgBase);

    // 监听列表
    private static Dictionary<string, MsgListener> listeners = new Dictionary<string, MsgListener>();

    static List<String> msgList = new List<string>();

    public static void AddEventListener(NetEvent netEvent, EventListener listener)
    {
        // Debug.Log("AddEventListener ---" + netEvent);
        if (eventListeners.ContainsKey(netEvent))
        {
            eventListeners[netEvent] += listener;
        }
        else
        {
            eventListeners[netEvent] = listener;
        }
    }

    public static void RemoveEventListener(NetEvent netEvent, EventListener listener)
    {
        if (eventListeners.ContainsKey(netEvent))
        {
            eventListeners[netEvent] -= listener;
            if (eventListeners[netEvent] == null)
            {
                eventListeners.Remove(netEvent);
            }
        }
    }

    public static void FireEvent(NetEvent netEvent, string err)
    {
        if (eventListeners.ContainsKey(netEvent))
        {
            eventListeners[netEvent](err);
        }
    }

    // 添加监听
    public static void AddListener(string msgName, MsgListener listener)
    {
        // Debug.Log("AddListener ---" + msgName);
        if (listeners.ContainsKey(msgName))
        {
            listeners[msgName] += listener;
        }
        else
        {
            listeners[msgName] = listener;
        }
    }

    public static void RemoveListener(string msgName, MsgListener listener)
    {
        if (listeners.ContainsKey(msgName))
        {
            listeners[msgName] -= listener;
            if (listeners[msgName] == null)
            {
                listeners.Remove(msgName);
            }
        }
    }

    // 分发消息
    public static void FireMsg(string msgName, MsgBase msgBase)
    {
        if (listeners.ContainsKey(msgName))
        {
            listeners[msgName](msgBase.ToString());
        }
    }

    public static bool is_connect_flag = false;

    // 获取描述
    public static string GetDesc()
    {

        if (socket == null || !socket.Connected)
        {
            BdUtils.log("*** GetDesc: return !");
            return "";
        }
        return socket.LocalEndPoint.ToString();
    }

    public static bool is_connected(bool send_msg_to_check = false)
    {
        bool ret = true;
        if (socket == null || !socket.Connected)
            ret = false;

        if (send_msg_to_check)
        {

            try
            {
                byte[] buffer = new byte[1];
                int received = socket.Receive(buffer, 0, 1, SocketFlags.None);
                if (received == 0)
                {
                    // Connection closed by the server
                    ret = false;
                    BdUtils.log(" --- send_msg_to_check: Connection closed by the server");
                }
            }
            catch (SocketException e)
            {
                if (e.ErrorCode == 10054)
                {
                    // Connection closed by the server
                    BdUtils.log(" --- send_msg_to_check 2: Connection closed by the server");
                }
                else
                {
                    // Handle other socket exception
                    BdUtils.log("*** send_msg_to_check: other socket exception");
                }
                ret = false;
            }
        }

        return ret;
    }
    private static void _OnConnectFail(string e)
    {
        Debug.Log("*** Socket Connect fail --- ", e);
        FireEvent(NetEvent.ConnectFail, e);
        isConnecting = false;

        is_connect_flag = false;
    }
    private static void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            Socket socket = (Socket)ar.AsyncState;
            socket.EndConnect(ar);

            if (!is_connected())
            {
                _OnConnectFail($"[ConnectCallback 1] --- 连接失败! socket.Connected: {socket.Connected}");
                return;
            }

            Debug.Log("*** Socket Connect Succ");
            FireEvent(NetEvent.ConnectSucc, "");
            isConnecting = false;
        }
        catch (SocketException ex)
        {
            _OnConnectFail("ConnectCallback 2" + ex.ToString());
        }
    }

    private static void InitialState()
    {
        // Socket
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        readBuff = new ByteArray(len_readbuff);
        writeQueue = new Queue<ByteArray>();
        isConnecting = false;
        isClosing = false;
        hasSendCloseMsg = false;
    }

    // 连接
    public static void Connect(string ip, int port)
    {
        if (socket != null && socket.Connected)
        {
            _OnConnectFail("[Connect] Connect fail, already connected!");
            return;
        }
        if (isClosing)
        {
            BdUtils.log("*** Connect fail, isClosing!");
            return;
        }


        InitialState();

        socket.NoDelay = true;
        isConnecting = true;
        hasSendCloseMsg = false;
        // 绑定端口
        // int bind_port = BdUtils.TimeUtils.get_random_number(8800, 8900);
        // socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), bind_port));
        // Connect (用同步方式简化代码)

        // socket.Connect(ip, port); // 这个没有错误处理
        socket.BeginConnect(ip, port, ConnectCallback, socket);  // 新版, 加上connect的callback

        socket.BeginReceive(readBuff.bytes, readBuff.writeIdx, readBuff.remain, 0, ReceiveCallback, socket);
    }

    public static void Close()
    {
        if (!is_connected())
        {
            return;
        }
        if (isConnecting)
            return;

        if (!hasSendCloseMsg)
        {
            var msg = new MsgClose();
            Send(msg);
            hasSendCloseMsg = true;
        }

        if (writeQueue.Count > 0)
        {
            isClosing = true;
        }
        else
        {
            socket.Close();
            FireEvent(NetEvent.Close, "");
        }
    }

    // Receive回调
    static int recursionCounter1 = 1;
    // static int recursionCounter2 = 1;

    // static long lastResetRecursionTime = 0;
    static char reset_flag;
    private static void ReceiveCallback(IAsyncResult ar)
    {

        if (!is_connected())
        {
            // BdUtils.log("*** ReceiveCallback: is_connected is false, return !");
            return;
        }

        // if (ar.AsyncState == null || ar.AsyncWaitHandle.WaitOne(0) == false)
        // {
        //     BdUtils.log("\n*** The server socket has been closed!");
        //     return;
        // }

        try
        {
            Socket socket = (Socket)ar.AsyncState;
            int count = socket.EndReceive(ar);  // 获取接收数据的长度
            // int count = -1;
            // try
            // {
            //     count = socket.EndReceive(ar);  // 获取接收数据的长度
            // }
            // catch (Exception e)
            // {
            //     var msg = $"*** socket.EndReceive接收错误, 可能是链接已关闭. error: {e}";
            //     BdUtils.log(msg, "\n--- \n\n");
            //     // throw new Exception(msg);
            //     return;
            // }

            readBuff.writeIdx += count;
            OnReceiveData();

            // 继续接受数据
            if (readBuff.remain < 8)
            {
                readBuff.MoveBytes();
                readBuff.Resize(readBuff.length * 2);
            }

            // System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
            // long timestamp = sw.ElapsedTicks / (System.Diagnostics.Stopwatch.Frequency / (1000L * 1000L));

            int prevent_stackoverflow = 1;
            if (BdUtils.conv_to_bool(prevent_stackoverflow))
            {
                if (recursionCounter1 >= 500)  // 短时间内大量循环, 则可能是服务器已经关闭
                {
                    // Console.Clear();
                    BdUtils.log("\n\n~~~~ [stackoverflow] recursionCounter1:", recursionCounter1, BdUtils.end_string, "\n\n");

                    hasSendCloseMsg = true;  // 不给服务端发送关闭msg
                    Close();

                    FireEvent(NetEvent.Close, "*** 服务端已关闭!");
                    // this.socket = null;
                    return;
                }

                recursionCounter1 += 1;

                var s = BdUtils.TimeUtils.get_time_string("ff");  // 每0.01秒清空一次`recursionCounter1`
                // BdUtils.log("\n\n\n\n~~~~ s:", s, BdUtils.end_string);

                if (s[1] == '1' && s[0] != reset_flag)
                {
                    BdUtils.log("\n\n\n\n~~~~ 111 recursionCounter1:", recursionCounter1);
                    // BdUtils.TimeUtils.sleep(0.5);
                    recursionCounter1 = 0;
                    reset_flag = s[0];
                }

                string current_time = BdUtils.TimeUtils.get_time_string("s4");
            }
            socket.BeginReceive(readBuff.bytes, readBuff.writeIdx, readBuff.remain, 0, ReceiveCallback, socket);
        }
        catch (SocketException e)
        {
            var error_reason = e.ToString();
            if (e.ErrorCode == 61)
            {
                error_reason = "无法连接到服务器!";
            }
            string msg = $"*** [ReceiveCallback], error: {error_reason} ********";
            // BdUtils.log(msg);
            _OnConnectFail(msg);

        }
    }

    public static void OnReceiveData()
    {
        // 消息长度
        if (readBuff.length <= head_len)
            return;

        // 解析bodyLength
        Int16 bodyLength = readBuff.ReadInt16();

        if (bodyLength < 0)
        {
            BdUtils.log($"*** 出现bodyLength[{bodyLength}]值错误的情况!");
            BdUtils.log($"[此时的缓冲区] readBuff = {System.Text.Encoding.UTF8.GetString(readBuff.bytes)}");
            return;
        }

        if (bodyLength > readBuff.length)  // 本条消息还没接收完
        {
            readBuff.readIdx -= head_len;  // 返还`head_len`字节的长度信息
            return;
        }

        // 消息体
        // string s = System.Text.Encoding.UTF8.GetString(readBuff, head_len, bodyLength);
        byte[] stringByte = new byte[bodyLength];
        readBuff.Read(stringByte, 0, bodyLength);
        string recvStr = System.Text.Encoding.UTF8.GetString(stringByte);

        if (BdUtils.is_null(recvStr))
        {
            BdUtils.log("! --- recvStr is_null !!!");
            BdUtils.TimeUtils.sleep(2);
            return;
        }

        // 消息处理
        lock (msgList)
            msgList.Add(recvStr);

        //继续读取消息
        if (readBuff.length > head_len)
        {
            OnReceiveData();
        }

    }

    // 发送
    public static void Send(string sendStr)
    {
        // BdUtils.log($"*** Send: sendStr {sendStr}");

        if (socket == null || !socket.Connected)
        {
            // BdUtils.log("*** Send: return !");
            // _OnConnectFail("Send: 连接失败!");
            return;
        }

        // 长度信息1 bodyLength
        byte[] bodyBytes = System.Text.Encoding.UTF8.GetBytes(sendStr);
        Int16 len = (Int16)bodyBytes.Length;
        byte[] lenBytes = BitConverter.GetBytes(len);
        if (!BitConverter.IsLittleEndian)
        {
            BdUtils.log("[Send] Reverse lenBytes");
            lenBytes.Reverse();
        }
        byte[] sendBytes = lenBytes.Concat(bodyBytes).ToArray();

        ByteArray ba = new ByteArray(sendBytes);
        int count = 0;
        // 这里实现`完整发送数据`的功能
        lock (writeQueue)
        {
            writeQueue.Enqueue(ba);
            count = writeQueue.Count;
        }

        if (writeQueue.Count == 1)
        {
            socket.BeginSend(ba.bytes, ba.readIdx, ba.length, 0, SendCallback, socket);
        }
    }
    public static void Send(object sendStr)
    {
        Send(sendStr.ToString());
    }


    public static void SendCallback(IAsyncResult ar)
    {
        try
        {
            Socket socket = (Socket)ar.AsyncState;
            int count = socket.EndSend(ar);

            ByteArray ba;

            // 判断是否发送完整
            lock (writeQueue)
            {
                ba = writeQueue.First();
            }
            ba.readIdx += count;

            if (ba.length == 0)  // 发送完整
            {
                lock (writeQueue)
                {
                    writeQueue.Dequeue();
                    if (writeQueue.Count() != 0)
                    {
                        ba = writeQueue.First();
                    }
                    else
                        ba = null;
                }

            }
            if (ba != null)  // 发送不完整, 或者发送完整且存在第二条数据
            {
                BdUtils.log($"--- ba | readIdx[{ba.readIdx}] | length[{ba.length}]");
                socket.BeginSend(ba.bytes, ba.readIdx, ba.length, 0, SendCallback, socket);
            }

        }
        catch (SocketException ex)
        {
            Debug.Log("Socket Send fail" + ex.ToString());
        }
    }

    // Update
    public static void Update()
    {
        // BdUtils.log($"~~~ NetManager.Update at {BdUtils.TimeUtils.get_time_string("s2", get_date: false)}");

        if (socket == null || !socket.Connected)
        {
            // BdUtils.log("*** Update: return !");
            // _OnConnectFail("Update: 连接失败!");
            return;
        }

        if (msgList.Count <= 0) return;

        String msgStr = "";
        lock (msgList)
        {
            msgStr = msgList[0];
            msgList.RemoveAt(0);
        }

        if (msgStr == "")
        {
            BdUtils.log("!!!!!");
            BdUtils.TimeUtils.sleep(1);
            return;
        }
        if (BdUtils.is_null(msgStr))
        {
            BdUtils.log("! --- Update msgStr is_null !!!");
            BdUtils.TimeUtils.sleep(1);
            return;
        }
        // BdUtils.log($"*** Update received msgStr: {msgStr}");

        var msg_dc = BdUtils.conv_json_to_dict(msgStr);
        // BdUtils.log("~~~~~ ", s, BdUtils.conv_json_to_dict(s, new string[] { "protoName" }));

        string protoName;
        try
        {
            protoName = msg_dc["protoName"].ToString();
        }
        catch (Exception e)
        {
            Console.Clear();
            BdUtils.log($"提取protoName出问题了... msg_dc:", msg_dc);
            throw new Exception(e.ToString());
        }

        // 监听回调
        if (listeners.ContainsKey(protoName))
        {
            listeners[protoName](msgStr);
        }
        else
        {
            MsgHandle.run_method_by_msg(msgStr, msg_dc);  // 使用`MsgHandle`类
        }

    }
}
